import pygame

from src.base_elements.landscape import Brick, Steel, Home, DestroyedHome
from src.base_elements.props import PropFactory
from src.constants import Direction, ExplosionType, EnemyTankType


class Bullet(pygame.sprite.Sprite):
    """
    通用的子弹类，玩家坦克和敌军坦克都使用该子弹
    """

    def __init__(self, direction=None, tank_rect=None, speed=6, can_destroy_steel=False):
        """
        初始化
        :param direction: 子弹移动的方向
        :param tank_rect: 坦克的坐标
        :param speed: 子弹移动的速度，单位为 6 像素点/帧
        :param can_destroy_steel: 子弹是否可以摧毁钢铁
        """
        super().__init__()
        # 子弹朝向
        self.direction = direction
        # 子弹移动速度，单位：像素点/祯
        self.speed = speed
        # 子弹是否可以摧毁钢铁
        self.can_destroy_steel = can_destroy_steel

        # 子弹是否存活
        self.is_alive = True
        # 子弹爆炸类型
        self.explosion_type = None
        # 用于记录是玩家一还是玩家二射出的子弹
        self.owner = None
        # 用于记录玩家击杀的敌方坦克类型
        self.destroyed_enemy_tank = None

        self.image = None
        self.rect = None
        self.explosion_images = []
        self._init_images()
        self._set_image_and_rect(tank_rect)

    def _init_images(self):
        """
        初始化图片
        """
        # 不同朝向的子弹图片
        self.up_bullet = pygame.image.load(r"assets/images/bullets/up_bullet.png")
        self.down_bullet = pygame.image.load(r"assets/images/bullets/down_bullet.png")
        self.left_bullet = pygame.image.load(r"assets/images/bullets/left_bullet.png")
        self.right_bullet = pygame.image.load(r"assets/images/bullets/right_bullet.png")

    def _set_image_and_rect(self, tank_rect):
        """
        设置图片以及图片的坐标
        """
        if self.direction == Direction.UP:
            self.image = self.up_bullet
            self.rect = self.image.get_rect()
            self.rect.left = tank_rect.left + 18
            self.rect.bottom = tank_rect.top + 1
        elif self.direction == Direction.DOWN:
            self.image = self.down_bullet
            self.rect = self.image.get_rect()
            self.rect.left = tank_rect.left + 18
            self.rect.top = tank_rect.bottom - 1
        elif self.direction == Direction.LEFT:
            self.image = self.left_bullet
            self.rect = self.image.get_rect()
            self.rect.right = tank_rect.left - 1
            self.rect.top = tank_rect.top + 18
        elif self.direction == Direction.RIGHT:
            self.image = self.right_bullet
            self.rect = self.image.get_rect()
            self.rect.left = tank_rect.right + 1
            self.rect.top = tank_rect.top + 18

    def update(
        self,
        landscape_group,
        prop_forbidden_landscape_group=None,
        tank_group=None,
        enemy_tank_group=None,
        player_tank_group=None,
        enemy_bullet_group=None,
        player_bullet_group=None,
        prop_group=None,
    ):
        """
        更新子弹的坐标，以及检测碰撞
        """
        self.rect = self.rect.move(self.speed * self.direction[0], self.speed * self.direction[1])

        # 如果子弹碰到边界，则子弹毁灭
        if self.rect.top < 3 or self.rect.bottom > 630 - 3 or self.rect.left < 3 or self.rect.right > 630 - 3:
            self.kill()
            self.is_alive = False
            self.explosion_type = ExplosionType.SMALL
            return self

        # 检查玩家子弹和敌方坦克
        if enemy_tank_group and player_tank_group:
            enemy_tanks = pygame.sprite.spritecollide(self, enemy_tank_group, False)
            for enemy_tank in enemy_tanks:
                if enemy_tank.level - 1 == 0:
                    self.kill()
                    self.is_alive = False
                    self.explosion_type = ExplosionType.LARGE
                    if enemy_tank.type == EnemyTankType.ENEMY_PROP:
                        prop = PropFactory().generate_prop(
                            player_tank_group=player_tank_group,
                            prop_forbidden_landscape_group=prop_forbidden_landscape_group,
                        )
                        prop_group.empty()
                        prop_group.add(prop)
                    tank_group.remove(enemy_tank)
                    enemy_tank_group.remove(enemy_tank)
                    self.destroyed_enemy_tank = enemy_tank
                    return self
                else:
                    self.kill()
                    self.is_alive = False
                    self.explosion_type = ExplosionType.SMALL
                    enemy_tank.change_level(enemy_tank.level - 1)
                    return self

        # 检测玩家子弹与敌方子弹的碰撞
        if enemy_bullet_group:
            enemy_bullets = pygame.sprite.spritecollide(self, enemy_bullet_group, True)
            if enemy_bullets:
                self.kill()
                self.is_alive = False
                self.explosion_type = ExplosionType.SMALL
                return self

        # 检查敌方子弹和玩家坦克的碰撞
        if player_tank_group and enemy_tank_group is None:
            player_tanks = pygame.sprite.spritecollide(self, player_tank_group, False)
            if player_tanks:
                self.kill()
                self.is_alive = False
                for player_tank in player_tanks:
                    if player_tank.shield:
                        self.explosion_type = ExplosionType.SMALL
                    else:
                        self.explosion_type = ExplosionType.LARGE
                        player_tank.kill()
                return self

        # 检查子弹和地形的碰撞。
        # 注意：子弹和地形的碰撞检查必须放在子弹和坦克的碰撞检查之后，否则会出现坦克在树林中无法被命中的问题。
        landscape_blocks = pygame.sprite.spritecollide(self, landscape_group, False)
        if landscape_blocks:
            for landscape_block in landscape_blocks:
                if isinstance(landscape_block, Brick) and not landscape_block.is_half_brick:
                    half_brick = landscape_block.get_half(self.direction)
                    landscape_group.remove(landscape_block)
                    landscape_group.add(half_brick)
                elif isinstance(landscape_block, Brick) and landscape_block.is_half_brick:
                    landscape_group.remove(landscape_block)
                if isinstance(landscape_block, Steel) and self.can_destroy_steel:
                    landscape_group.remove(landscape_block)
                if isinstance(landscape_block, Home):
                    landscape_group.remove(landscape_block)
                    landscape_group.add(DestroyedHome())
                if landscape_block.can_cross_by_bullet:
                    continue
                self.kill()
                self.is_alive = False
                self.explosion_type = ExplosionType.SMALL
            return self

        return self
